// Copyright (C) 2023 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import m from 'mithril';

import {exists} from '../base/utils';

import {HTMLInputAttrs} from './common';
import {Menu, MenuItem} from './menu';
import {scheduleFullRedraw} from './raf';
import {TextInput} from './text_input';

export class Select implements m.ClassComponent<HTMLInputAttrs> {
  view({attrs, children}: m.CVnode<HTMLInputAttrs>) {
    return m('select.pf-select', attrs, children);
  }
}

export interface FilterableSelectAttrs {
  // Whether to show a search box. Defaults to false.
  filterable?: boolean;
  // The values to show in the select.
  values: string[];
  // Called when the user selects an option.
  onSelected: (value: string) => void;
  // If set, only the first maxDisplayedItems will be shown.
  maxDisplayedItems?: number;
  // Whether the input field should be focused when the widget is created.
  autofocusInput?: boolean;
}

// A select widget with a search box, allowing the user to filter the options.
export class FilterableSelect
  implements m.ClassComponent<FilterableSelectAttrs>
{
  searchText = '';

  view({attrs}: m.CVnode<FilterableSelectAttrs>) {
    const filteredValues = attrs.values.filter((name) => {
      return name.toLowerCase().includes(this.searchText.toLowerCase());
    });

    const displayedValues =
      attrs.maxDisplayedItems === undefined
        ? filteredValues
        : filteredValues.slice(0, attrs.maxDisplayedItems);

    const extraItems =
      exists(attrs.maxDisplayedItems) &&
      Math.max(0, filteredValues.length - attrs.maxDisplayedItems);

    // TODO(altimin): when the user presses enter and there is only one item,
    // select the first one.
    // MAYBE(altimin): when the user presses enter and there are multiple items,
    // select the first one.
    return m(
      'div',
      m(
        '.pf-search-bar',
        m(TextInput, {
          oninput: (event: Event) => {
            const eventTarget = event.target as HTMLTextAreaElement;
            this.searchText = eventTarget.value;
            scheduleFullRedraw();
          },
          onload: (event: Event) => {
            if (!attrs.autofocusInput) return;
            const eventTarget = event.target as HTMLTextAreaElement;
            eventTarget.focus();
          },
          value: this.searchText,
          placeholder: 'Filter...',
          className: 'pf-search-box',
        }),
        m(
          Menu,
          ...displayedValues.map((value) =>
            m(MenuItem, {
              label: value,
              onclick: () => attrs.onSelected(value),
            }),
          ),
          Boolean(extraItems) && m('i', `+${extraItems} more`),
        ),
      ),
    );
  }
}
